[inject ../templates/en.xd]
[set-title C++ | Language Criticism | xigoi ]
[show-title C++ Language Criticism]
[p Everything that applies to [link C; c.html] also applies to C++. This article contains only things that don't apply to C.]
[p The [link C++ FQA; http://yosefk.com/c++fqa/index.html] has a lot of great points, so go read it too. ]
[def tio; link; [link Try it online!; [arg-expand link]]]
[def comparison; items; [<div> .comparison; [arg items]]]
[def compared; langname lang code tio;
  [<div> .compared;
    [<h6> [arg langname]]
    [code-block [arg-expand lang]; [arg-expand code]]
    [tio [arg-expand tio]]
  ]
]
[section Overall philosophy;
  [p I believe that a programming language should be designed to make simple things simple and complex things as simple as possible. C++ is designed to make simple things complex and complex things even more complex. For example, a program to read space-separated numbers from STDIN, sort them and again output them space-separated:]
  [comparison
    [compared Python 3; python; [raw
nums = [int(inp) for inp in input().split()]
print(*sorted(nums))
    ]; https://tio.run/##K6gsycjPM/7/P680t1jBViE6M69EIzOvQFMhLb9IAcgAYhBVWqKhqVdckJMJpGO5CopAyrSK84tKUlM0QFo1Nf//NzY0UTA0VbBUMDJTMFUwNgUA]
    [compared Nim; nim; [raw
import std/[strutils, sequtils, algorithm]

let nums = stdin.readLine.splitWhitespace.mapIt(it.parseInt)
echo nums.sorted.mapIt($it).join(" ")
    ]; https://tio.run/##LY3LCsIwEADv@YqleGhBIrVG6MEPKHj3IB5Cs9iVvMxuvz8@6G0OM0ykUCuFnIoAizvcWcoq5HkPjO@NrH@mQrKEh1IeBeIaGC4/n6IuaN2VImrOnuS2kCBnO6MONk/SkuhsC@MUpVM4L@lfa/4O0W3OjqTTr0SxbaDpah36E/QGRjiewcBgPg]
    [compared Haskell; haskell; [raw
import Data.List

main = interact $ (++ "\n") . unwords . map show
                . sort
                . map (read :: String -> Int) . words
    ]; https://tio.run/##bcwxC8IwFATgPb/iKA6VYqDWCBZ0chHcXF0eNthg81KSJ/35sXUUbzoO7uspveww5Oz8GKLgTEL66pIo5ckxjnAsNtJDsEJZVSjuXKyh8eYpxC7NzdOI1IdJ4ScaaSb/zMujjJY6tC1uEh0/sTnhwrLIXzfnpt6hNjhgu4dBYz4]
    [compared C++; cpp; [raw
#include <iostream>
#include <vector>
#include <algorithm>

int main() {
  std::vector<int> nums;
  std::string inp;
  while (std::getline(std::cin, inp, ' ')) {
    nums.emplace_back(std::stoi(inp));
  }
  std::sort(nums.begin(), nums.end());
  std::string sep = "";
  for (int num : nums) {
    std::cout << sep << num;
    sep = " ";
  }
  std::cout << std::endl;
}
    ]; https://tio.run/##VY/NTsMwEITveYpRONSRAlIpQSIJfRXkOiZd1bEtx4ED6rMH/7SlnKzdmfl2LKx9HIVY1wfSQi2DRE9m9k7yaV/87b6k8Mbdb7gajSN/DLaCtMfESbMKPwUw@6Ftc6IP0h56mebuKgQ46RGkbVx9H0lJsKSM0ivSMg@CdB1NNTbYVBmMRHqSk1VcyI8DFyd2YRpiwVxVkXm@nTLOsxQ5yDHWqy8APbBsvW80S4t3lGXcfxoHFr8V/GhT6lohtzOLR9@nTHiC3mUxM1D@63FzxyEcV11xXtfd9gXbBm94fkWDXfML]
  ]
]
[section Features;
  [list
    Despite being a very large language, C++ doesn't have basic features like sum types or pattern matching.;
    Many features duplicate other features, adding their own advantages and drawbacks (and more unnecessary syntactic rules to learn). Examples: initializer lists, [code cpp; typedef] / [code cpp; using], [code cpp; #define] / [code cpp; constexpr], [code cpp; [raw char[]]] / [code cpp; std::string], [code cpp; [raw int[]]] / [code cpp; std::array<int>], [code cpp; printf] / [code cpp; cout], [code cpp; struct] / [code cpp; class];
  ]
]
[section Syntax;
  [p C++ took the horrible syntax of C and somehow managed to make it even worse.]
  [list
    The [link most vexing parse; https://en.wikipedia.org/wiki/Most_vexing_parse] (and similar rules). I can't fathom what could possibly cause someone to think this is a good idea.;
    [link Parsing C++ is literally undecidable.; https://blog.reverberate.org/2013/08/parsing-c-is-literally-undecidable.html];
    Using less-than and greater-than signs as brackets, which hinders auto-pairing and complicates parsing while also looking ugly. [link Here's a longer explanation from another person.; https://soc.me/languages/stop-using-for-generics];
    The semicolon after a [code cpp; struct] / [code cpp; class] definition. Just why?;
    Keywords that have multiple meanings depending on where you use them: [code cpp; static], [code cpp; using], [code cpp; typename].;
    The keyword [code cpp; const] is used to declare immutable variables (not constants, for which there is [code cpp; constexpr]) and it can be placed in various positions inside a type, which completely changes its meaning.;
    Who decided that [code cpp; ::] is a good path separator?;
  ]
]
[section Standard library;
  [list
    Despite being quite extensive, the standard library doesn't have basic things like
      [list
        basic functions for working with strings (split, join);
        functional abstractions (map, filter, fold, …) [() C++20 partially solves this with “range adaptors” (what a weird name), but the usage is unbearably cumbersome];
        optional/result types;
      ];
    Using the term [" vector] for a resizable array, even though the word has a completely different meaning in mathematics.;
    There is no convenient way to pass a whole array/vector/list to a function, you have to do something like [code cpp; std::sort(arr.begin(), arr.end())].;
    Weird function names: from C crypticisms ([code cpp; stoi], [code cpp; fscanf]) to unusual words ([code cpp; emplace_back]).;
    Idiomatically, it's required to write [code cpp; std::] between everything from the standard library, which makes the code repetitive and unreadable. Who would have guessed that [code cpp; sort] is a standard library function if it wasn't for the prefix?;
  ]
]
[section Tooling;
  [list
    Error messages.
    [list
      If you try to search a “vector” (array) of a wrong type… Credit goes to [link this StackExchange answer; https://codegolf.stackexchange.com/a/10470/98955].
      [code-block cpp; [raw
#include <vector>
#include <algorithm>

int main() {
    int a;
    std::vector<std::vector<int>> v;
    std::vector<std::vector<int>>::const_iterator it = std::find(v.begin(), v.end(), a);
}
      ]][tio https://tio.run/##jY1BDoIwEEX3PcUkbiBRDlCwVzF1OtZJoCVl7MZ49lJgoUv/6uXl/3yc54tHLOXEAceXIxgyocRk1NfY0cfE8pyMUhwEJsuhaeGtoGYTtt9xEaf1MR9@uVaMgfxHSWuMYZEbCyVbLbDA9Zg8OLgmd3fy2/kZckdVVLBtrz6lrA]
      The error message (compiled with GCC 10.2.0) has 148 lines with about 12 kB of content, starting with:
      [<pre> [<samp> [raw
In file included from /usr/include/c++/10.2.0/bits/stl_algobase.h:71,
                 from /usr/include/c++/10.2.0/vector:60,
                 from error.cpp:1:
/usr/include/c++/10.2.0/bits/predefined_ops.h: In instantiation of ‘bool __gnu_cxx::__ops::_Iter_equals_val<lt;_Value>::operator()(_Iterator) [with _Iterator = __gnu_cxx::__normal_iterator<lt;std::vector<lt;int>*, std::vector<lt;std::vector<lt;int> > >; _Value = const int]’:
/usr/include/c++/10.2.0/bits/stl_algobase.h:1932:14:   required from ‘_RandomAccessIterator std::__find_if(_RandomAccessIterator, _RandomAccessIterator, _Predicate, std::random_access_iterator_tag) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator<lt;std::vector<lt;int>*, std::vector<lt;std::vector<lt;int> > >; _Predicate = __gnu_cxx::__ops::_Iter_equals_val<lt;const int>]’
/usr/include/c++/10.2.0/bits/stl_algobase.h:1977:23:   required from ‘_Iterator std::__find_if(_Iterator, _Iterator, _Predicate) [with _Iterator = __gnu_cxx::__normal_iterator<lt;std::vector<lt;int>*, std::vector<lt;std::vector<lt;int> > >; _Predicate = __gnu_cxx::__ops::_Iter_equals_val<lt;const int>]’
/usr/include/c++/10.2.0/bits/stl_algo.h:3902:28:   required from ‘_IIter std::find(_IIter, _IIter, const _Tp&) [with _IIter = __gnu_cxx::__normal_iterator<lt;std::vector<lt;int>*, std::vector<lt;std::vector<lt;int> > >; _Tp = int]’
error.cpp:7:87:   required from here
/usr/include/c++/10.2.0/bits/predefined_ops.h:268:17: error: no match for ‘operator==’ (operand types are ‘std::vector<lt;int>’ and ‘const int’)
  268 |  { return *__it == _M_value; }
      |           ~~~~~~^~~~~~~~~~~
In file included from /usr/include/c++/10.2.0/bits/stl_algobase.h:67,
                 from /usr/include/c++/10.2.0/vector:60,
                 from error.cpp:1:
/usr/include/c++/10.2.0/bits/stl_iterator.h:1064:5: note: candidate: ‘template<lt;class _IteratorL, class _IteratorR, class _Container> bool __gnu_cxx::operator==(const __gnu_cxx::__normal_iterator<lt;_IteratorL, _Container>&, const __gnu_cxx::__normal_iterator<lt;_IteratorR, _Container>&)’
 1064 |     operator==(const __normal_iterator<lt;_IteratorL, _Container>& __lhs,
      |     ^~~~~~~~
/usr/include/c++/10.2.0/bits/stl_iterator.h:1064:5: note:   template argument deduction/substitution failed:
      ]]];
      If you forget a semicolon… Credit goes to [link this StackExchange answer; https://codegolf.stackexchange.com/a/205268/98955].
      [code-block cpp; [raw
constexpr double pi = 3.0 // An engineer approximation

#include <iostream>

int main() {
  std::cout << "Enter the radius: " << std::flush;
  double radius;
  std::cin >> radius;
  std::cout << "Area: " << pi * radius * radius << std::endl;
}
      ]]
      [tio https://tio.run/##ZY7NCsIwEITveYpBLypoBW9tLXjwQWKy6kK7CfkBQXz2WrXVg7dl@PabMd6vL8b0vXESE918gHX51BI8Y4/dZouiwEFAcmEhCtDeB3fjTid2otScxbTZEmp2MQXSXaMUS0KnWRZL3BUQky1L43JCXWN2lDRo0pUQtOUcS8xe@Rs6tzleq@FlHPEhqq@DBU3zl07mw1A/2ob1q5H7HVMLiW0r9ej7Jw]
      The error message (compiled with GCC 10.2.0) has 3244 lines with about 250 kB of content, starting with:
      [<pre> [<samp> [raw
In file included from /usr/include/c++/10.2.0/iostream:38,
  from error.cpp:3:
/usr/include/c++/10.2.0/x86_64-pc-linux-gnu/bits/c++config.h:258:1: error: expected ‘,’ or ‘;’ before ‘namespace’
  258 | namespace std
      | ^~~~~~~~~
In file included from /usr/include/c++/10.2.0/iosfwd:40,
  from /usr/include/c++/10.2.0/ios:38,
    from /usr/include/c++/10.2.0/ostream:38,
      from /usr/include/c++/10.2.0/iostream:39,
        from error.cpp:3:
/usr/include/c++/10.2.0/bits/postypes.h:98:11: error: ‘ptrdiff_t’ does not name a type
  98 |   typedef ptrdiff_t streamsize; // Signed integral type
     |           ^~~~~~~~~
/usr/include/c++/10.2.0/bits/postypes.h:41:1: note: ‘ptrdiff_t’ is defined in header ‘<cstddef>’; did you forget to ‘#include <cstddef>’?
  40 | #include <cwchar> // For mbstate_t
 +++ |+#include <cstddef>
  41 | 
In file included from /usr/include/c++/10.2.0/bits/exception_ptr.h:40,
  from /usr/include/c++/10.2.0/exception:147,
    from /usr/include/c++/10.2.0/ios:39,
      from /usr/include/c++/10.2.0/ostream:38,
        from /usr/include/c++/10.2.0/iostream:39,
          from error.cpp:3:
/usr/include/c++/10.2.0/new:126:26: error: declaration of ‘operator new’ as non-function
  126 | _GLIBCXX_NODISCARD void* operator new(std::size_t) _GLIBCXX_THROW (std::bad_alloc)
      |                          ^~~~~~~~
/usr/include/c++/10.2.0/new:126:44: error: ‘size_t’ is not a member of ‘std’; did you mean ‘size_t’?
  126 | _GLIBCXX_NODISCARD void* operator new(std::size_t) _GLIBCXX_THROW (std::bad_alloc)
      |                                            ^~~~~~
      ]]]
      I guess the fourth line does tell you that you missed a semicolon (if you have the patience to scroll to it), but it's not exactly clear where.;
      Would you prefer an error that I actually encountered? Here is a simplified version of some code I wrote in a programming contest:
      [code-block cpp; [raw
#include <algorithm>
#include <iostream>
#include <numeric>
#include <string>
#include <vector>

std::string decrypt(std::string& k, std::string& m) {
  std::vector<std::string> c(k.length());
  int n = m.length() % k.length() == 0 ? m.length() / k.length() : m.length() / k.length() + 1;
  int a = 0;
  for (std::string& s : c) {
    for (int i = 0; i < n; i++) {
      s += a >= m.length() ? ' ' : m[a];
      a++;
    }
  }
  std::vector<int> j(k.length());
  std::iota(j.begin(), j.end(), 0);
  std::sort(j.begin(), j.end(), [&k](int x, int y) { return k[x] < k[y]; });
  std::vector<int> q(k.length());
  for (int i = 0; i < k.length(); i++) {
    q[j[i]] = i;
  }
  std::string r = "";
  for (int i = 0; i < n; i++) {
    for (int ii = 0; ii < k.length(); ii++) {
      char h = c[q[ii]][i];
      if (c != ' ') {
        r += c;
      }
    }
  }
  return r;
}

int main() {
  std::string k;
  std::getline(std::cin, k);
  std::string m;
  std::getline(std::cin, m);
  std::cout << decrypt(k, m) << std::endl;
}
      ]]
      [tio https://tio.run/##fZPbboMwDIbveQqv0zYQrOtuy6EPgrhgaQrhENoQplYTz87MqQldOyFE8P/F/LYDOR7fE0K67plxUjR7Cl5cJJVgMi0DQwVZVUtB40WMNyUVjOghhBhP9Mg3JbISgWHUcr/djjrsKRGXozS12CvkDizeSwt@DBhjYxZP0wMgZr4uKE9kalqWiyTjEjj4UF7D8AKKAd@HDex0@UOXtw8VGz7n/DHm3/Qvh0rA0n@NGcjoeZL7DWzYgA8POD5seyawMrB9TBgsHO/gDS/0EsaRO4GxbY/L1hhvvSf4kQCy214MBKtkbGbrL5owbloOZGvK9/1io5i6EvIuE77m0VDB2Rkqv6BxEFQ2gkMeniMsKA8vkQutSqZbOt1autcShSx6cwqzkEURcszVS56Oj0BhtXqUc9lmRczIn@8uhkLSWECKKAlPIUMTaGSeAzuASeDJ70ekdgD6wUGSmWoXo5o6JlyjNYzeRxn3jVZHe6opvzYxobJgnI6HizDuQK6Na6TLf@hS0aRqJHje9X/Le7UPDCoOukBbXfcL]
      The error message does tell you where the error is, but you have to scroll through 228 lines with over 22 kB of content.;
    ]
  ]
]
